package main

import (
	"container/list"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"reflect"
	"regexp"
	"strings"

	"github.com/beevik/etree"
	"github.com/thinkeridea/go-extend/exnet"
)

func externalIP() (net.IP, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return nil, err
	}
	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp == 0 {
			continue // interface down
		}
		if iface.Flags&net.FlagLoopback != 0 {
			continue // loopback interface
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return nil, err
		}
		for _, addr := range addrs {
			ip := getIpFromAddr(addr)
			if ip == nil {
				continue
			}
			return ip, nil
		}
	}
	return nil, errors.New("connected to the network?")
}

func getIpFromAddr(addr net.Addr) net.IP {
	var ip net.IP
	switch v := addr.(type) {
	case *net.IPNet:
		ip = v.IP
	case *net.IPAddr:
		ip = v.IP
	}
	if ip == nil || ip.IsLoopback() {
		return nil
	}
	ip = ip.To4()
	if ip == nil {
		return nil // not an ipv4 address
	}

	return ip
}

func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

//RSA加密
// plainText 要加密的数据
// path 公钥匙文件地址
func RSA_Encrypt(plainText []byte, path string) []byte {
	//打开文件
	file, err := os.Open(path)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	//读取文件的内容
	info, _ := file.Stat()
	buf := make([]byte, info.Size())
	file.Read(buf)
	//pem解码
	block, _ := pem.Decode(buf)
	//x509解码

	publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		panic(err)
	}
	//类型断言
	publicKey := publicKeyInterface.(*rsa.PublicKey)
	//对明文进行加密
	cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText)
	if err != nil {
		panic(err)
	}
	//返回密文
	return cipherText
}

//RSA解密
// cipherText 需要解密的byte数据
// path 私钥文件路径
func RSA_Decrypt(cipherText []byte, path string) []byte {
	//打开文件
	file, err := os.Open(path)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	//获取文件内容
	info, _ := file.Stat()
	buf := make([]byte, info.Size())
	file.Read(buf)
	//pem解码
	block, _ := pem.Decode(buf)
	//X509解码
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		panic(err)
	}
	//对密文进行解密
	plainText, _ := rsa.DecryptPKCS1v15(rand.Reader, privateKey, cipherText)
	//返回明文
	return plainText
}

var publicKey = []byte(`-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaDlKuhf7D5QZAUamuwV6pe3MJ
F4FGo/LSglI0CTq80v7vRCqnYwV/PIhZL+GaSUTLHrIUGCChhNW8u9XpWLM2C3HX
KJ1aZXE2zEUGuYIRZiZoH+Yd82jE0iP9IvLouGuwfLHzqhXPUZHW74w5Nopu62I6
BZruTiZQHK3T+EGL+wIDAQAB
-----END PUBLIC KEY-----`)

func RsaEncrypt(origData []byte) ([]byte, error) {
	block, _ := pem.Decode(publicKey)
	if block == nil {
		return nil, errors.New("public key error")
	}
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	pub := pubInterface.(*rsa.PublicKey)
	return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
}

func entryHandler(w http.ResponseWriter, r *http.Request) {
	ip := exnet.ClientPublicIP(r)
	if ip == "" {
		ip = exnet.ClientIP(r)
	}
	log.Printf("请求ip: %s method: %s", ip, r.Method)
	scheme := "http://"
	if r.TLS != nil {
		scheme = "https://"
	}
	log.Println(strings.Join([]string{scheme, r.Host, r.RequestURI}, ""))
	defer r.Body.Close()
	con, _ := ioutil.ReadAll(r.Body) //获取post的数据
	requestXml := string(con)
	log.Println("接收到数据:" + requestXml)
	xmlRes := "<?xml version=\"1.0\" encoding=\"UTF-8\"?><service><Head><SvcCd>{svcCd}</SvcCd><SvcScn>{svcScn}</SvcScn><CnlTp>1</CnlTp><CnsmrSysId>1</CnsmrSysId><CnsmrSeqNo>Z00246</CnsmrSeqNo><PvdrSysId></PvdrSysId><PvdrSeqNo></PvdrSeqNo><SrcCnsmrSysId></SrcCnsmrSysId><SrcCnsmrSeqNo></SrcCnsmrSeqNo><TxnDt></TxnDt><TxnTm></TxnTm><RetCd>00000</RetCd><SubRetCd></SubRetCd><RetMsg></RetMsg><ErrLocCd></ErrLocCd><FileFlg>0</FileFlg><FileNm></FileNm><FileVerfCd></FileVerfCd><SvcVerNo></SvcVerNo><InstId></InstId><TlrNo></TlrNo></Head><Body><{statusTag}>{RetRslt}</{statusTag}><{msgTag}>{DscMsg1}</{msgTag}><{urlTag}>{bsnTp}</{urlTag}><{resultTag}>{result}</{resultTag}></Body></service>"
	xmlRes = strings.Replace(xmlRes, "{svcCd}", svcCd, -1)
	xmlRes = strings.Replace(xmlRes, "{svcScn}", svcScn, -1)
	xmlRes = strings.Replace(xmlRes, "{statusTag}", statusTag, -1)
	xmlRes = strings.Replace(xmlRes, "{msgTag}", msgTag, -1)
	xmlRes = strings.Replace(xmlRes, "{urlTag}", urlTag, -1)
	xmlRes = strings.Replace(xmlRes, "{resultTag}", resultTag, -1)
	if len(requestXml) == 0 {
		errMsg := "empty request xml"
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}
	isOnlyPost := false
	if strings.ToUpper(r.Method) != "POST" && isOnlyPost {
		errMsg := "method " + r.Method + " is not support"
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}
	doc := etree.NewDocument()
	if err := doc.ReadFromString(requestXml); err != nil {
		log.Println("read xml error:", err)
		xmlRes = genResult(xmlRes, "500", err.Error(), "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}
	notesIdElement := doc.FindElement("./service/Head/" + tmlNoTag)
	if notesIdElement == nil {
		errMsg := tmlNoTag + " is not a valid document"
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}
	notesId := notesIdElement.Text()
	auhoNoBase64Element := doc.FindElement("./service/Body/" + authNoTag)
	if auhoNoBase64Element == nil {
		errMsg := authNoTag + " is not a valid document"
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}
	auhoNoBase64 := auhoNoBase64Element.Text()
	eqmtNoBase64Element := doc.FindElement("./service/Body/" + eqmtNoTag)
	if eqmtNoBase64Element == nil {
		errMsg := eqmtNoTag + " is not a valid document"
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}
	eqmtNoBase64 := eqmtNoBase64Element.Text()
	bsnTpBase64Element := doc.FindElement("./service/Body/" + urlTag)
	if bsnTpBase64Element == nil {
		errMsg := urlTag + " is not a valid document"
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}
	bsnTpBase64 := bsnTpBase64Element.Text()
	bsnLrgFldBase64Element := doc.FindElement("./service/Body/" + resultTag)
	if bsnLrgFldBase64Element == nil {
		errMsg := resultTag + " is not a valid document"
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}
	bsnLrgFldBase64 := bsnLrgFldBase64Element.Text()
	authNo := decodeBase64(auhoNoBase64)
	eqmtNo := decodeBase64(eqmtNoBase64)
	bsnTp := decodeBase64(bsnTpBase64)
	bsnLrgFld := decodeBase64(bsnLrgFldBase64)
	log.Printf("authNo: %s eqmtNo: %s bsnTp: %s bsnLrgFld: %s", authNo, eqmtNo, bsnTp, bsnLrgFld)

	jsonRes := make(map[string]interface{})
	err := json.Unmarshal([]byte(bsnLrgFld), &jsonRes)
	if err != nil {
		log.Println(err)
		errMsg := err.Error()
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}
	url := ""
	if jsonRes["url"] != nil {
		url = jsonRes["url"].(string)
		if !strings.Contains(url, "http://") {
			if defaultRequestRoot != "" {
				url = defaultRequestRoot + url
			} else {
				errMsg := "url is invalid(" + url + ")"
				log.Println(errMsg)
				xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
				w.Write([]byte(xmlRes))
				return
			}
		} else {
			if strings.Contains(url, defaultRequestHost) && strings.Contains(url, defaultRequestHost+"ychbhq/") {
				url = strings.Replace(url, defaultRequestHost, defaultRequestHost+"ychbhq/", 1)
			}
		}
	} else {
		errMsg := "url is invalid"
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}
	method := ""
	if jsonRes["method"] != nil {
		method = strings.ToUpper(jsonRes["method"].(string))
	} else {
		errMsg := "method is invalid"
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}
	body := ""
	if jsonRes["body"] != nil {
		body = jsonRes["body"].(string)
	}

	log.Printf("url: %s method: %s body: %s", url, method, body)
	client := &http.Client{}
	reqest, err := http.NewRequest(method, url, strings.NewReader(body))
	if err != nil {
		log.Println(err)
		errMsg := err.Error()
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}
	reqest.Header.Set("Content-Type", "application/json; charset=utf-8")

	tokenMap := map[string]string{}
	match, _ := regexp.MatchString("[0-9]{6}||", authNo)
	matchNotesId, _ := regexp.MatchString("[0-9]{6}", notesId)
	if match {
		authNo = authNo[0:6]
	} else if !match && authNo == "" && matchNotesId {
		authNo = notesId
	}
	log.Println(authNo)
	tokenMap["id"] = authNo
	tokenMap["pw"] = ""
	tokenMap["su"] = "eaip"
	tokenMap["ip"] = ".*"
	tokenMap["ep"] = ""
	rsaEncoded, _ := json.Marshal(tokenMap)
	log.Println(string(rsaEncoded))
	// token := RSA_Encrypt(rsaEncoded, "public.pem")
	token, _ := RsaEncrypt(rsaEncoded)
	authorization := "token " + encodeBase64ForByte(token)
	log.Printf("authorization: %s", authorization)
	reqest.Header.Set("Authorization", authorization)

	reqest.Header.Set("notesId", authNo)
	reqest.Header.Set("deviceToken", eqmtNo)

	//处理返回结果
	response, err := client.Do(reqest)
	if err != nil {
		log.Println(err)
		errMsg := err.Error()
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}

	defer response.Body.Close() //ok, most of the time :-)
	bodyRes, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Println(err)
		errMsg := err.Error()
		log.Println(errMsg)
		xmlRes = genResult(xmlRes, "500", errMsg, "500", "", true)
		w.Write([]byte(xmlRes))
		return
	}

	log.Println(string(bodyRes))

	xmlRes = strings.Replace(xmlRes, "{RetRslt}", encodeBase64("200"), -1)
	xmlRes = strings.Replace(xmlRes, "{DscMsg1}", encodeBase64("success"), -1)
	xmlRes = strings.Replace(xmlRes, "{bsnTp}", encodeBase64("200"), -1)
	xmlRes = strings.Replace(xmlRes, "{result}", encodeBase64(string(bodyRes)), -1)
	log.Printf("返回结果: %s", xmlRes)
	w.Write([]byte(xmlRes))
}

func genResult(xmlRes string, code string, message string, url string, result string, isErr bool) string {
	xmlRes = strings.Replace(xmlRes, "{RetRslt}", encodeBase64(code), -1)
	xmlRes = strings.Replace(xmlRes, "{DscMsg1}", encodeBase64(message), -1)
	xmlRes = strings.Replace(xmlRes, "{bsnTp}", encodeBase64(url), -1)
	if isErr {
		msgMap := map[string]string{}
		msgMap["message"] = message
		msg, _ := json.Marshal(msgMap)
		xmlRes = strings.Replace(xmlRes, "{result}", encodeBase64(string(msg)), -1)
	} else {
		xmlRes = strings.Replace(xmlRes, "{result}", encodeBase64(result), -1)
	}
	log.Printf("返回结果: %s", xmlRes)
	return xmlRes
}

func encodeBase64ForByte(strbytes []byte) string {
	encoded := base64.StdEncoding.EncodeToString(strbytes)
	return encoded
}

func encodeBase64(str string) string {
	strbytes := []byte(str)
	encoded := encodeBase64ForByte(strbytes)
	return encoded
}

func decodeBase64(str string) string {
	// Base64 Standard Decoding
	sDec, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		log.Printf("Error decoding string: %s ", err.Error())
		return str
	}
	return string(sDec)
}

const (
	Separator = os.PathSeparator // 路径分隔符（分隔路径元素）
)

func cors(f http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")                                                            // 允许访问所有域，可以换成具体url，注意仅具体url才能带cookie信息
		w.Header().Add("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token") //header的类型
		w.Header().Add("Access-Control-Allow-Credentials", "true")                                                    //设置为true，允许ajax异步请求带cookie信息
		w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")                             //允许请求方法
		w.Header().Set("content-type", "application/json;charset=UTF-8")                                              //返回数据格式是json
		if r.Method == "OPTIONS" {
			w.WriteHeader(http.StatusNoContent)
			return
		}
		f(w, r)
	}
}

var defaultRequestHost = defaultRequestHost
var defaultRequestRoot = "http://168.38.6.86:18080/ychbhq/"
var svcCd = "60120012"
var svcScn = "20"
var authNoTag = "AuthNo"
var eqmtNoTag = "EqmtNo"
var statusTag = "RetRslt"
var msgTag = "DscMsg1"
var urlTag = "BsnTpDsc"
var resultTag = "MsgCntnt"
var tmlNoTag = "TmlNo"

func main() {
	fmt.Println(
		`-Auhor 张维
-Phone 18627101045`)
	port := "18080"
	pathArr := list.New()
	pathArr.PushBack("/svc/entry.do")
	pathArr.PushBack("/cib/svc/entry.do")
	pathArr.PushBack("/svc/entry")
	pathArr.PushBack("/cib/svc/entry")
	configName := "config.json"
	isConfigExist, err := PathExists(configName)
	if err != nil {
		log.Println(err)
	}
	if isConfigExist {
		fmt.Println("config.json配置文件存在")
		file, err := os.Open(configName)
		if err != nil {
			panic(err)
		}
		defer file.Close()
		//读取文件的内容
		info, _ := file.Stat()
		buf := make([]byte, info.Size())
		file.Read(buf)
		configStr := string(buf)
		log.Println(configStr)
		configJson := make(map[string]interface{})
		err = json.Unmarshal(buf, &configJson)
		if err != nil {
			log.Println(err)
		} else {
			if configJson["defaultRequestRoot"] != "" && configJson["defaultRequestRoot"] != nil {
				defaultRequestRoot = configJson["defaultRequestRoot"].(string)
			}
			if configJson["port"] != "" && configJson["port"] != nil {
				port = configJson["port"].(string)
			}
			if configJson["paths"] != "" && configJson["paths"] != nil {
				paths := configJson["paths"]
				if reflect.TypeOf(paths).Kind() == reflect.Slice || reflect.TypeOf(paths).Kind() == reflect.Array {
					s := reflect.ValueOf(paths)
					for i := 0; i < s.Len(); i++ {
						pathArr.PushBack(s.Index(i).Interface().(string))
					}
				}
			}
			if configJson["svcCd"] != "" && configJson["svcCd"] != nil {
				svcCd = configJson["svcCd"].(string)
			}
			if configJson["svcScn"] != "" && configJson["svcScn"] != nil {
				svcScn = configJson["svcScn"].(string)
			}
			if configJson["authNoTag"] != "" && configJson["authNoTag"] != nil {
				authNoTag = configJson["authNoTag"].(string)
			}
			if configJson["eqmtNoTag"] != "" && configJson["eqmtNoTag"] != nil {
				eqmtNoTag = configJson["eqmtNoTag"].(string)
			}
			if configJson["statusTag"] != "" && configJson["statusTag"] != nil {
				statusTag = configJson["statusTag"].(string)
			}
			if configJson["msgTag"] != "" && configJson["msgTag"] != nil {
				msgTag = configJson["msgTag"].(string)
			}
			if configJson["urlTag"] != "" && configJson["urlTag"] != nil {
				urlTag = configJson["urlTag"].(string)
			}
			if configJson["resultTag"] != "" && configJson["resultTag"] != nil {
				resultTag = configJson["resultTag"].(string)
			}
			if configJson["tmlNoTag"] != "" && configJson["tmlNoTag"] != nil {
				tmlNoTag = configJson["tmlNoTag"].(string)
			}
		}
	} else {
		fmt.Println(
			`================================================================
--config.json配置文件不存在,可忽略--
内容为json字符串
defaultRequestRoot(字符串):转发地址,默认为 http://168.38.6.86:18080/ychbhq/
port(字符串):entry服务端口,默认18080
paths(字符串数组):entry请求地址,默认["/svc/entry","/svc/entry.do","/cib/svc/entry","/cib/svc/entry.do"]
svcCd(字符串):默认60120012
svcScn(字符串):默认20
authNoTag(字符串):默认AuthNo
eqmtNoTag(字符串):默认EqmtNo
statusTag(字符串):默认RetRslt
msgTag(字符串):默认DscMsg1
urlTag(字符串):默认BsnTpDsc
resultTag(字符串):默认MsgCntnt
tmlNoTag(字符串):默认TmlNo
================================================================`)
	}

	log.Println("serve start")
	ip, err := externalIP()
	if err != nil {
		log.Println(err)
	}
	log.Println(ip.String() + ":" + port)
	for e := pathArr.Front(); e != nil; e = e.Next() {
		http.HandleFunc(e.Value.(string), cors(entryHandler))
	}
	http.ListenAndServe(":"+port, nil)
}
